#include "LoadState.h"
#include "BPhysicsEngine.h"
#include "Input.h"
#include "Engine.h"
#include "ServerState.h"
#include "ClientState.h"
#include <sstream>

static void TW_CALL StartServer(void *clientData)
{  
    LoadState* s = (LoadState*)clientData;
    Engine::Instance()->RequestChange(new ServerState);
}
static void TW_CALL StartClient(void *clientData)
{  
    LoadState* s = (LoadState*)clientData;
    Engine::Instance()->RequestChange(new ClientState);
}
LoadState::LoadState()
{

}
void LoadState::Update(int dt)
{
}
void LoadState::Draw()
{
    //------->And so it begins...
    TEST(Engine::Instance()->GetDevice()->BeginScene());

    //this sets up the VIEW and PROJECTION matrices in the camera class,
    //does NOT set them in the shader
    m_camera->Prepare();

    //
    RenderUI(GET_TEXTURE("loading.png"));

    //end the scene
    TEST(Engine::Instance()->GetDevice()->EndScene());
    //present the scene
    Engine::Instance()->GetDevice()->Present(NULL, NULL, NULL, NULL );
}
void LoadState::Initialise()
{
    m_PEngine = new BPhysicsEngine;
    //compiles the shader
    ShaderInit();

    // Create the light projection matrix 
    float piover2 = D3DX_PI/2;
    TEST(m_mainEffect->SetFloat( "g_fCosTheta", cosf( piover2/2 )));
    D3DXMatrixPerspectiveFovLH(&m_lightProjMatrix, piover2, (float)Engine::Instance()->GetScreenRes(0)/
        (float)(float)Engine::Instance()->GetScreenRes(1), 100, 10000.0f);


    //MakeUI!
    CreateUI();
    //Set up the cameras
    SetUpCameras();

    // font
    D3DXCreateFont( Engine::Instance()->GetDevice(), 16, 0, FW_THIN, 0, FALSE, DEFAULT_CHARSET,
        OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
        L"Arial", &m_font   );

    Engine::Instance()->LLoadTexture("Textures/", "loading.png");

    //reset all data to default,
    Reset();
}
void LoadState::CleanUp()
{
    if(m_PEngine != NULL)
    {
        delete m_PEngine;
    }
    m_PEngine = NULL;

    if(m_texturedQuad)
        m_texturedQuad->Release();

    if(m_font)
        m_font->Release();

    delete m_camera;
    TwDefine("Startup visible=false");
    Engine::Instance()->GetResource()->FlushTexture("loading.png");
}
void LoadState::RenderUI(Texture tex)
{
    //create an identity matrix
    D3DXMATRIXA16 identity;
    D3DXMatrixIdentity(&identity);
    //reset the matrixes in the shader
    TEST(m_mainEffect->SetMatrix("g_mWorld", &identity));
    TEST(m_mainEffect->SetMatrix("g_mView", &identity));
    TEST(m_mainEffect->SetMatrix("g_mProj", &identity));

    if(tex)
    {
        // Apply the technique contained in the effect 
        TEST(m_mainEffect->SetTechnique("Texture"));
        //set the texture
        TEST(m_mainEffect->SetTexture("Diffuse", tex));
    }
    UINT passes = 0;
    TEST(Engine::Instance()->GetDevice()->SetVertexDeclaration(CustomVertex::s_dcl));
    TEST(Engine::Instance()->GetDevice()->SetStreamSource( 0, m_texturedQuad, 0, sizeof( CustomVertex ) ));


    TEST(m_mainEffect->Begin( &passes, 0 ));
    for(unsigned int  iPass = 0; iPass < passes; iPass++ )
    {
        TEST(m_mainEffect->BeginPass( iPass ));

        TEST(Engine::Instance()->GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2 ));

        TEST(m_mainEffect->EndPass());
    }
    TEST(m_mainEffect->End());
    //Draw the UI BARS
    TwDraw();
}
void LoadState::Reset()
{
    m_PEngine->CleanActors();   
    m_camera->SetPosition(Vec3(0,35,0));
}
Camera* LoadState::GetCamera()
{
    return m_camera;
}
ID3DXEffect* LoadState::GetEffect()
{
    return m_mainEffect;
}
BPhysicsEngine* LoadState::GetPhysicsEngine()
{
    return m_PEngine;
}

void LoadState::NotifyKeyPressDirectInput(bool pressed, int whichKey, KeyState state, int clientID)
{

}
void LoadState::NotifyKeyPressSDL(int type, int state, int key, int whichClient)
{
}
void LoadState::HandleMessage(const char* message)
{

}
BPhysicsActor* LoadState::CreateNetworkedActor(int whichModel, bool perception, int ID)
{
    return NULL;
}
void LoadState::CreatePlayer(int clientID, int Actor)
{

}
void LoadState::DestroyPlayer(int clientID, int actorID)
{

}
NetworkedActor* LoadState::FindNetworkedActor(int ID)
{
    return NULL;
}

void LoadState::ShaderInit() 
{
    LPD3DXBUFFER err;
#ifdef _DEBUG
    HRESULT hr = D3DXCreateEffectFromFile( Engine::Instance()->GetDevice(), 
        L"../src/Scripts/GodRays.fx", NULL, NULL
        , D3DXFX_NOT_CLONEABLE | D3DXSHADER_DEBUG, NULL, &m_mainEffect, &err );
    if(hr != D3D_OK)
        hr = D3DXCreateEffectFromFile( Engine::Instance()->GetDevice(), 
        L"Scripts/GodRays.fx", NULL, NULL
        , D3DXFX_NOT_CLONEABLE | D3DXSHADER_DEBUG, NULL, &m_mainEffect, &err );
#else
    HRESULT hr = D3DXCreateEffectFromFile( Engine::Instance()->GetDevice(), 
        L"../src/Scripts/GodRays.fx", NULL, NULL, D3DXSHADER_OPTIMIZATION_LEVEL3, NULL, &m_mainEffect, &err );
    if(hr != D3D_OK)
        hr = D3DXCreateEffectFromFile( Engine::Instance()->GetDevice(), 
        L"Scripts/GodRays.fx", NULL, NULL, D3DXSHADER_OPTIMIZATION_LEVEL3, NULL, &m_mainEffect, &err );
#endif

    if(hr != D3D_OK)
    {
        MessageBoxA(0, (char*)err->GetBufferPointer(), "Error", MB_OKCANCEL);
    }
    m_texturedQuad = Engine::Instance()->CreateTexturedQuad(&m_quadVerts);
    //preparing the stats for the shader
    D3DXVECTOR4 ambLight(0.1f,0.1f,0.1f,0.1f);
    D3DXVECTOR4 difLight(0.4f,0.4f,0.4f,0.4f);
    D3DXVECTOR4 specLight(1.0f,1.0f,1.0f,1.0f);

    //setting the stats in the shader
    TEST(m_mainEffect->SetVector("gAmbientLight", &ambLight));
    TEST(m_mainEffect->SetVector("gDiffuseLight", &difLight));
    TEST(m_mainEffect->SetVector("gSpecularLight", &specLight));
}
void LoadState::SetUpCameras()
{
    float piover2 = D3DX_PI/2;
    //1
    m_camera = new Camera;
    m_camera->SetProjection(1, 1500.0f, (float)Engine::Instance()->GetScreenRes(0)  / 
        (float)Engine::Instance()->GetScreenRes(1) , piover2/2);
    m_camera->SetUpVector(Vec3(0,1,0));
    //start position for the free floating camera
    m_camera->SetPosition(Vec3(0,0,0));
    m_camera->SetDirection(Vec3(1,0,0));
} 
void LoadState::CreateUI()
{
    /************************************************************************/
    /* STUFF FOR UI                                                         */
    /************************************************************************/
    m_optionsBar = TwNewBar("Startup");
    TwDefine("Startup alpha= 0");
    TwDefine("Startup position = '0 0'");
    TwDefine("Startup iconifiable=false");
    TwDefine("Startup movable=false");
    TwDefine("Startup resizable=false");
    TwDefine("Startup fontresizable=false");
    //SIZE
    std::string size = "Startup size = '";
    std::stringstream sizeSS;
    sizeSS << Engine::Instance()->GetScreenRes(0) << " " << 80 <<"'";
    size +=sizeSS.str();
    TwDefine(size.c_str());
    //buttons
    (TwAddButton(m_optionsBar, "Create as Server", (TwButtonCallback)&StartServer, this, "Starts the server"));
    (TwAddButton(m_optionsBar, "Create as Client", (TwButtonCallback)&StartClient, this, "Stars the client"));
    //Labels
}
